package cc.rengu.oltp.utility.util;

import java.util.Objects;

public class MACUtil {
    private static final int ENCRYPT = 1;

    /**
     * 验证mac
     *
     * @param sm4Key   国密密钥
     * @param macBlock MAC验证原始字符串
     * @param mac      计算的MAC值
     * @return true-验证通过，false-验证失败
     */
    public static boolean verifySm4Mac(String sm4Key, String macBlock, String mac) {
        String macStr = genSm4Mac(sm4Key, macBlock);
        String macDst = ByteUtil.bytesToHexString(macStr.substring(0, 8).getBytes());
        if (mac.equals(macDst)) {
            return true;
        } else {
            System.out.println("mac=" + mac + ",macDst=" + macDst);
            return false;
        }
    }

    /**
     * 3des验证mac
     *
     * @param macKey   3DES密钥
     * @param macBlock MAC验证原始字符串
     * @param mac      计算的MAC值
     * @return true-验证通过，false-验证失败
     */
    public static boolean verify3DesMac(String macKey, String macBlock, String mac) {
        String macDst = gen3DesMac(macKey, macBlock);
        return mac.equals(macDst);
    }

    /**
     * 3des算法生成mac
     *
     * @param macKey   3DES密钥
     * @param macBlock MAC验证原始字符串
     * @return MAC值
     */
    public static String gen3DesMac(String macKey, String macBlock) {
        byte[] out;
        byte[] in = ByteUtil.hexStringToByte(macBlock);
        int inLen = in.length;
        byte[] key = ByteUtil.hexStringToByte(macKey);
        int reset = inLen % 8;
        int round;
        if (reset == 0) {
            round = inLen / 8;
        } else {
            round = inLen / 8 + 1;
        }
        byte[] inAdd = new byte[8 * round];
        System.arraycopy(in, 0, inAdd, 0, inLen);
        //加密 64bit
        for (int i = 0; i < round - 1; i++) {
            byte[] inBuf = new byte[8];
            byte[] nextBuf = new byte[8];
            System.arraycopy(inAdd, 8 * i, inBuf, 0, 8);
            out = DES3Util.encryptMode3DESDouble(key, inBuf);
            System.arraycopy(inAdd, 8 * (i + 1), nextBuf, 0, 8);
            if (null != out) {
                for (int j = 0; j < 8; j++) {
                    inAdd[8 * (i + 1) + j] = (byte) (out[j] ^ nextBuf[j]);
                }
            }
        }
        byte[] lastBytes = new byte[8];
        System.arraycopy(inAdd, 8 * (round - 1), lastBytes, 0, 8);
        //最后一次加密
        out = DES3Util.encryptMode3DESDouble(key, lastBytes);
        return Objects.requireNonNull(ByteUtil.bytesToHexString(out)).substring(0, 8);
    }

    /**
     * sm4算法生成mac
     *
     * @param sm4Key   国密密钥
     * @param macBlock MAC计算的原始字符串
     * @return MAC值
     */
    public static String genSm4Mac(String sm4Key, String macBlock) {
        byte[] out = new byte[16];

        byte[] in = macBlock.trim().getBytes();
        int inLen = in.length;

        byte[] key = ByteUtil.hexStringToByte(sm4Key);
        int reset = inLen % 16;
        int round;
        if (reset == 0) {
            round = inLen / 16;
        } else {
            round = inLen / 16 + 1;
        }
        byte[] inAdd = new byte[16 * round];
        System.arraycopy(in, 0, inAdd, 0, inLen);
        //加密 128bit
        for (int i = 0; i < round - 1; i++) {
            byte[] inBuf = new byte[16];
            byte[] nextBuf = new byte[16];
            System.arraycopy(inAdd, 16 * i, inBuf, 0, 16);
            SM4Util.sms4(inBuf, 16, key, out, ENCRYPT);
            System.arraycopy(inAdd, 16 * (i + 1), nextBuf, 0, 16);
            for (int j = 0; j < 16; j++) {
                inAdd[16 * (i + 1) + j] = (byte) (out[j] ^ nextBuf[j]);
            }
        }
        byte[] lastBytes = new byte[16];
        System.arraycopy(inAdd, 16 * (round - 1), lastBytes, 0, 16);
        //最后一次加密
        SM4Util.sms4(lastBytes, 16, key, out, ENCRYPT);
        return Objects.requireNonNull(ByteUtil.bytesToHexString(out)).substring(0, 16);
    }
}